home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / acstream / acstream.pas < prev    next >
Pascal/Delphi Source File  |  1995-12-22  |  21KB  |  877 lines

  1. unit acStream;
  2.  
  3. {
  4.   Project: Non-Component Persistent Object Streaming
  5.  
  6.   Alan Ciemian
  7.   Copyright ⌐ 1995. All Rights Reserved
  8.  
  9.  
  10.   Overview
  11.   ========
  12.   Implements basic classes for persistent object streaming.
  13.  
  14.   TacStreamable defines the interface for streamable objects.
  15.   TacObjStream  defines the interface for object capable streams.
  16.  
  17.   TacFileObjStream implements a file based object stream.
  18.   TacMemoryObjStream implements a memory based object stream.
  19. }
  20.  
  21. interface
  22.  
  23. uses
  24.   Classes, SysUtils;
  25.  
  26.  
  27. type
  28.   TacStreamableClassName = string[63]; { Only 63 chars of identifiers are significant }
  29.   TacStreamableClassId   = Integer;    { Identifies class of streamed objects }
  30.   TacStreamableClassIdx  = Integer;    { Index into class list }
  31.  
  32. type
  33.   TacObjStreamMode =
  34.     (
  35.     osmClosed,  { stream not open }
  36.     osmInput,   { for reading only }
  37.     osmOutput,  { for writing only, starts with empty stream }
  38.     osmAppend   { for writing only, starts with current contents }
  39.     );
  40.   TacObjStreamModes = set of TacObjStreamMode;
  41.  
  42. type  { Standard stream header. Starts every TacObjStream. }
  43.   TacObjStreamHeader = record
  44.     Signature        : array[0..7] of Char;
  45.     Version          : LongInt;
  46.     ClassTableOffset : LongInt;
  47.   end;
  48.  
  49. const
  50.   DefaultObjStreamHeader : TacObjStreamHeader =
  51.     (
  52.     Signature        : 'ACSTREAM';
  53.     Version          : $00000000;
  54.     ClassTableOffset : $00000000
  55.     );
  56.  
  57. type  { TacObjStream exception classes }
  58.   EacObjStream = class(Exception)
  59.   { Base class for TacObjStream Exceptions }
  60.   end;
  61.  
  62.   EacObjStreamInvalid = class(EacObjStream)
  63.   { Unexpected stream format, header unrecognized }
  64.   end;
  65.  
  66.   EacObjStreamWrongMode = class(EacObjStream)
  67.   { Stream is in the wrong mode for requested operation }
  68.   end;
  69.  
  70.  
  71. type
  72.   TacObjStream = class;  { Forward }
  73.  
  74.   TacStreamableClass = class of TacStreamable;
  75.   TacStreamable = class(TPersistent)
  76.   protected
  77.     { Centralized field initialization }
  78.     procedure InitFields; virtual;
  79.     { Stream interface }
  80.     constructor CreateFromStream(Stream: TacObjStream);
  81.     procedure SaveToStream  (Stream: TacObjStream); virtual; abstract;
  82.     procedure ReadFromStream(Stream: TacObjStream); virtual; abstract;
  83.     { Property methods }
  84.     function  GetAsString: String; virtual;
  85.   public
  86.     { Constructors }
  87.     constructor Create;
  88.     constructor CreateClone(const Other: TacStreamable);
  89.     { Properties }
  90.     property  AsString: String
  91.               read GetAsString;
  92.   end;
  93.  
  94.   TacObjStream = class(TObject)
  95.   private
  96.     FMode       : TacObjStreamMode;    { Access mode }
  97.     FHeader     : TacObjStreamHeader;  { Stream header }
  98.     FClassTable : TStringList;         { In-memory class lookup table }
  99.     { Stream header management }
  100.     procedure SaveStreamHeader;
  101.     procedure ReadStreamHeader;
  102.     { Class table management }
  103.     procedure PrepareClassTable(const Mode: TacObjStreamMode);
  104.     procedure SaveClassTable;
  105.     procedure ReadClassTable;
  106.     function  AddClassRef(const Obj: TacStreamable): TacStreamableClassId;
  107.   protected
  108.     { Abstract internal stream interface }
  109.     function  GetStream: TStream; virtual; abstract;
  110.     procedure OpenStream(const Mode: TacObjStreamMode); virtual; abstract;
  111.     procedure CloseStream; virtual; abstract;
  112.     { Error handling }
  113.     procedure ValidateStreamMode(const Modes: TacObjStreamModes);
  114.     procedure ObjStreamError(Exc: Exception); virtual;
  115.     { Placeholders for user added headers }
  116.     procedure SaveHeader; virtual;
  117.     procedure ReadHeader; virtual;
  118.   public
  119.     { Construction/Destruction }
  120.     constructor Create;
  121.     destructor  Destroy; override;
  122.     { Opening and closing stream }
  123.     procedure OpenForInput;
  124.     procedure OpenForOutput;
  125.     procedure OpenForAppend;
  126.     procedure Close;
  127.     { Save and Read methods for streaming objects }
  128.     procedure SaveObject(const Obj: TacStreamable);
  129.     function  ReadObject(const Obj: TacStreamable): TacStreamable;
  130.     { Methods used by objects to read/write their data }
  131.     procedure SaveBuffer(const Buffer; Count: Longint);
  132.     procedure ReadBuffer(var Buffer; Count: Longint);
  133.     procedure SaveCStr(const CStr: PChar);
  134.     function  ReadCStr: PChar;
  135.   end;
  136.  
  137.   TacFileObjStream = class(TacObjStream)
  138.   private
  139.     FFilename   : TFilename;
  140.     FFileStream : TFileStream;
  141.   protected
  142.     { Required internal stream interface }
  143.     function  GetStream: TStream; override;
  144.     procedure OpenStream(const Mode: TacObjStreamMode); override;
  145.     procedure CloseStream; override;
  146.   public
  147.     { Construction/Destruction }
  148.     constructor Create(const Filename: TFilename);
  149.     destructor  Destroy; override;
  150.     { Properties }
  151.     property Filename: TFilename
  152.              read FFilename;
  153.   end;
  154.  
  155.   TacMemoryObjStream = class(TacObjStream)
  156.   private
  157.     FMemoryStream : TMemoryStream;
  158.   protected
  159.     { Required internal stream interface }
  160.     function  GetStream: TStream; override;
  161.     procedure OpenStream(const Mode: TacObjStreamMode); override;
  162.     procedure CloseStream; override;
  163.   public
  164.     { Construction/Destruction }
  165.     constructor Create;
  166.     destructor  Destroy; override;
  167.   end;
  168.  
  169.  
  170. const { Simulating static class fiels }
  171.   TacFileObjStream_BackupExt : string[4] = '.BAK';
  172.  
  173.  
  174. implementation
  175.  
  176.  
  177. { TacStreamable implementation }
  178.  
  179.  
  180. {
  181. Create creates a default instance.
  182. }
  183. constructor TacStreamable.Create;
  184. begin
  185.   inherited Create;
  186.   InitFields;
  187. end;
  188.  
  189.  
  190. {
  191. CreateClone is a copy constructor. It creates an instance that
  192.   duplicates another assignment compatible instance.
  193. }
  194. constructor TacStreamable.CreateClone
  195.   (
  196.   const Other : TacStreamable
  197.   );
  198. begin
  199.   Create;
  200.   Assign(Other);
  201. end;
  202.  
  203.  
  204. {
  205. CreateFromStream creates an instance from a stream.
  206. }
  207. constructor TacStreamable.CreateFromStream
  208.   (
  209.   Stream : TacObjStream
  210.   );
  211. begin
  212.   Create;
  213.   ReadFromStream(Stream);
  214. end;
  215.  
  216.  
  217. {
  218. InitFields allows derived classes to specify default values for
  219.   its fields. Used by all the constructors directly or indirectly.
  220. }
  221. procedure TacStreamable.InitFields;
  222. begin
  223. end;
  224.  
  225.  
  226. {
  227. GetAsString returns a string representation of the object. Optional
  228.   but very useful for objects placed in lists.
  229. }
  230. function  TacStreamable.GetAsString;
  231. begin
  232.   Result := '';
  233. end;
  234.  
  235.  
  236. { TacObjStream implementation }
  237.  
  238.  
  239. {
  240. Create initializes the ObjStream instance.
  241. At this point no actual stream has been opened.
  242. }
  243. constructor TacObjStream.Create;
  244. begin
  245.   inherited Create;
  246.   FMode       := osmClosed;
  247.   FHeader     := DefaultObjStreamHeader;
  248.   FClassTable := TStringList.Create;
  249. end;
  250.  
  251.  
  252. {
  253. Destroy cleans up the ObjStream instance.
  254. }
  255. destructor TacObjStream.Destroy;
  256. begin
  257.   { Make sure actual stream is closed }
  258.   if ( FMode <> osmClosed ) then Close;
  259.  
  260.   { Free the class table }
  261.   FClassTable.Free;
  262.  
  263.   inherited Destroy;
  264. end;
  265.  
  266.  
  267. {
  268. ObjStreamError is a default exception processor. It just raises
  269.   the passed exception. Subclasses can override to modify TacObjStream
  270.   exceptions in one place instead of at each use.
  271. }
  272. procedure TacObjStream.ObjStreamError(Exc: Exception);
  273. begin
  274.   raise Exc;
  275. end;
  276.  
  277.  
  278. {
  279. ValidateStreamMode checks that the stream is in the expected mode.
  280. Raises exception if mode is unexpected.
  281. }
  282. procedure TacObjStream.ValidateStreamMode
  283.   (
  284.   const Modes : TacObjStreamModes
  285.   );
  286. begin
  287.   if ( not (FMode in Modes) ) then
  288.     begin
  289.     ObjStreamError(EacObjStreamWrongMode.Create('Operation is invalid for current stream mode.'));
  290.     end;
  291. end;
  292.  
  293.  
  294. {
  295. SaveStreamHeader writes the stream header and then calls the virtual
  296.   SaveHeader method to allow subclasses to save their own headers.
  297. }
  298. procedure TacObjStream.SaveStreamHeader;
  299. begin
  300.   with  GetStream  do
  301.     begin
  302.     { Seek to start of stream }
  303.     Seek(0, soFromBeginning);
  304.     { Save standard stream header }
  305.     WriteBuffer(FHeader, SizeOf(FHeader));
  306.     end;
  307.  
  308.   { Save user stream header }
  309.   SaveHeader;
  310. end;
  311.  
  312.  
  313. {
  314. ReadStreamHeader reads and verifies the stream header and then calls the virtual
  315.   ReadHeader method to allow subclasses to read their own headers.
  316. }
  317. procedure TacObjStream.ReadStreamHeader;
  318. begin
  319.   with  GetStream  do
  320.     begin
  321.     { Seek to start of stream }
  322.     Seek(0, soFromBeginning);
  323.     { Read standard stream header }
  324.     ReadBuffer(FHeader, SizeOf(FHeader));
  325.     { Validate standard stream header }
  326.     if ( FHeader.Signature <> DefaultObjStreamHeader.Signature ) then
  327.       begin
  328.       ObjStreamError(EacObjStreamInvalid.Create('Invalid acStream Format'));
  329.       end;
  330.  
  331.     { Read and validate user stream header }
  332.     ReadHeader;
  333.     end;
  334. end;
  335.  
  336.  
  337. {
  338. PrepareClassTable sets up the string list that is used for the class table.
  339. }
  340. procedure TacObjStream.PrepareClassTable
  341.   (
  342.   const Mode : TacObjStreamMode
  343.   );
  344. begin
  345.   { Empty class table }
  346.   FClassTable.Clear;
  347.  
  348.   case  Mode  of
  349.     osmInput :
  350.       begin  { Need unsorted class table }
  351.       FClassTable.Sorted := False;
  352.       end;
  353.     osmOutput,
  354.     osmAppend :
  355.       begin  { Need sorted class table }
  356.       FClassTable.Sorted     := True;
  357.       FClassTable.Duplicates := dupIgnore;
  358.       end;
  359.     end;
  360. end;
  361.  
  362.  
  363. {
  364. SaveClassTable appends the class table to the end of the stream.
  365.   Should only be called for output streams.
  366. }
  367. procedure TacObjStream.SaveClassTable;
  368. var
  369.   EntryCnt     : TacStreamableClassIdx;
  370.   EntryIdx     : TacStreamableClassIdx;
  371.   ObjClassName : TacStreamableClassName;
  372.   ObjClassId   : TacStreamableClassId;
  373. begin
  374.   with  GetStream  do
  375.     begin
  376.     { Seek to end of file }
  377.     Seek(0, soFromEnd);
  378.  
  379.     { Save class table offset in header }
  380.     FHeader.ClassTableOffset := Position;
  381.  
  382.     { Write size of class table }
  383.     EntryCnt := FClassTable.Count;
  384.     WriteBuffer(EntryCnt, SizeOf(EntryCnt));
  385.     { Write entries in form [class name][class id] }
  386.     for EntryIdx := 0 to (EntryCnt - 1) do
  387.       begin
  388.       ObjClassName := FClassTable.Strings[EntryIdx];
  389.       ObjClassId   := TacStreamableClassId(FClassTable.Objects[EntryIdx]);
  390.       WriteBuffer(ObjClassName, Length(ObjClassName) + 1);
  391.       WriteBuffer(ObjClassId,   SizeOf(ObjClassId));
  392.       end;
  393.     end;
  394. end;
  395.  
  396.  
  397. {
  398. ReadClassTable builds the class table from the stream.
  399.   Called for osmInput and osmAppend streams.
  400.   Stream offset of table is determined from stream header.
  401. }
  402. procedure TacObjStream.ReadClassTable;
  403. var
  404.   EntryCnt     : TacStreamableClassIdx;
  405.   EntryIdx     : TacStreamableClassIdx;
  406.   ObjClassName : TacStreamableClassName;
  407.   ObjClassId   : TacStreamableClassId;
  408. begin
  409.   with  GetStream  do
  410.     begin
  411.     { Position stream pointer to class table }
  412.     Seek(FHeader.ClassTableOffset, soFromBeginning);
  413.  
  414.     { Read size of class table }
  415.     ReadBuffer(EntryCnt, SizeOf(EntryCnt));
  416.  
  417.     if ( FMode = osmInput ) then
  418.       begin  { Expand list to proper size }
  419.       for EntryIdx := 0 to (EntryCnt - 1) do
  420.         begin
  421.         FClassTable.Add('');
  422.         end;
  423.       end;
  424.  
  425.     { Read entries and update table }
  426.     for EntryIdx := 0 to (EntryCnt - 1) do
  427.       begin
  428.       { Read in the class name and stream specific class id }
  429.       ReadBuffer(ObjClassName[0], 1);
  430.       ReadBuffer(ObjClassName[1], Ord(ObjClassName[0]));
  431.       ReadBuffer(ObjClassId,      SizeOf(ObjClassId));
  432.  
  433.       if ( FMode = osmInput ) then
  434.         begin
  435.         { Insert class names at index identified by class id }
  436.         FClassTable.Strings[ObjClassId] := ObjClassName;
  437.         { Lookup and save class type ref in associated object field }
  438.         FClassTable.Objects[ObjClassId] := TObject(FindClass(ObjClassName));
  439.         end
  440.       else  { FMode = osmAppend }
  441.         begin
  442.         { Insert class name, stuff class id in object ref }
  443.         FClassTable.AddObject(ObjClassName, TObject(ObjClassId));
  444.         end;
  445.       end;
  446.     end;
  447. end;
  448.  
  449.  
  450. {
  451. AddClassRef adds a new class type to the class table and returns the
  452.   associated class id. If the class is already in the table just returns
  453.   its class id. Class id is stored in the string list
  454.   as the object reference.
  455. }
  456. function  TacObjStream.AddClassRef
  457.   (
  458.   const Obj : TacStreamable
  459.   ): TacStreamableClassId;
  460. var
  461.   ObjClassName : TacStreamableClassName;
  462.   ObjClassIdx  : TacStreamableClassIdx;
  463. begin
  464.   { Get the class name }
  465.   ObjClassName := Obj.ClassName;
  466.   { Look for class ref already in table }
  467.   ObjClassIdx  := FClassTable.IndexOf(ObjClassName);
  468.   if ( ObjClassIdx <> -1 ) then
  469.     begin  { Class in table, return class id }
  470.     Result := TacStreamableClassId(FClassTable.Objects[ObjClassIdx]);
  471.     end
  472.   else
  473.     begin  { New Class, add class and return new class id }
  474.     Result := FClassTable.Count;
  475.     FClassTable.AddObject(ObjClassName, TObject(Result));
  476.     end;
  477. end;
  478.  
  479.  
  480. {
  481. SaveHeader is a placeholder for subclasses to implement saving
  482.   additional header info.
  483. }
  484. procedure TacObjStream.SaveHeader;
  485. begin
  486. end;
  487.  
  488.  
  489. {
  490. ReadHeader is a placeholder for subclasses to implement reading
  491.   additional header info.
  492. }
  493. procedure TacObjStream.ReadHeader;
  494. begin
  495. end;
  496.  
  497.  
  498. {
  499. OpenForInput
  500. Prepares and opens the stream for inputting.
  501. }
  502. procedure TacObjStream.OpenForInput;
  503. var
  504.   DataOffset : LongInt;
  505. begin
  506.   ValidateStreamMode([osmClosed]);
  507.  
  508.   { Setup class table }
  509.   PrepareClassTable(osmInput);
  510.  
  511.   { Open up the actual stream }
  512.   OpenStream(osmInput);
  513.   FMode := osmInput;
  514.  
  515.   { Read Header }
  516.   ReadStreamHeader;
  517.   { Save position of start of data area }
  518.   DataOffset := GetStream.Position;
  519.   { Read Class Table }
  520.   ReadClassTable;
  521.   { Seek back to data area }
  522.   GetStream.Seek(DataOffset, soFromBeginning);
  523. end;
  524.  
  525.  
  526. {
  527. OpenForOutput
  528. Prepares and opens the stream for outputting.
  529. }
  530. procedure TacObjStream.OpenForOutput;
  531. begin
  532.   ValidateStreamMode([osmClosed]);
  533.  
  534.   { Setup class table }
  535.   PrepareClassTable(osmOutput);
  536.  
  537.   { Open up the actual stream }
  538.   OpenStream(osmOutput);
  539.   FMode := osmOutput;
  540.  
  541.   { Save a default stream header }
  542.   SaveStreamHeader;
  543. end;
  544.  
  545.  
  546. {
  547. OpenForAppend
  548. Prepares and opens the stream for appending.
  549. }
  550. procedure TacObjStream.OpenForAppend;
  551. var
  552.   DataOffset : LongInt;
  553. begin
  554.   ValidateStreamMode([osmClosed]);
  555.  
  556.   { Setup class table }
  557.   PrepareClassTable(osmAppend);
  558.  
  559.   { Open up the actual stream }
  560.   OpenStream(osmAppend);
  561.  
  562.   { Mode starts as osmInput so subclasses can call Read methods for header }
  563.   FMode := osmInput;
  564.  
  565.   { Read Header }
  566.   ReadStreamHeader;
  567.   { Save position where new data will start }
  568.   DataOffset := FHeader.ClassTableOffset;
  569.  
  570.   { Now set real mode }
  571.   FMode := osmAppend;
  572.  
  573.   { Read Class Table }
  574.   ReadClassTable;
  575.   { Seek back to data append position }
  576.   GetStream.Seek(DataOffset, soFromBeginning);
  577. end;
  578.  
  579.  
  580. {
  581. Close
  582. Closes the stream.
  583. }
  584. procedure TacObjStream.Close;
  585. begin
  586.   ValidateStreamMode([osmInput, osmOutput, osmAppend]);
  587.   case  FMode  of
  588.     osmInput  :
  589.       begin  { Nothing special to do }
  590.       end;
  591.     osmOutput,
  592.     osmAppend :
  593.       begin  { Need to update class table and stream header }
  594.       SaveClassTable;
  595.       SaveStreamHeader;
  596.       end;
  597.     end;
  598.  
  599.   { Now close the actual stream }
  600.   CloseStream;
  601.   FMode := osmClosed;
  602. end;
  603.  
  604.  
  605. {
  606. SaveBuffer
  607. Main method for saving arbitrary data to the stream.
  608. }
  609. procedure TacObjStream.SaveBuffer(const Buffer; Count: Longint);
  610. begin
  611.   ValidateStreamMode([osmOutput, osmAppend]);
  612.   GetStream.WriteBuffer(Buffer, Count);
  613. end;
  614.  
  615.  
  616. {
  617. ReadBuffer
  618. Main method for reading arbitrary data to the stream.
  619. }
  620. procedure TacObjStream.ReadBuffer(var Buffer; Count: Longint);
  621. begin
  622.   ValidateStreamMode([osmInput]);
  623.   GetStream.ReadBuffer(Buffer, Count);
  624. end;
  625.  
  626.  
  627. {
  628. SaveObject
  629. Saves a TacStreamable object to the stream prefixed by its class Id.
  630. If Obj parameter is nil, nothing is saved.
  631. }
  632. procedure TacObjStream.SaveObject
  633.   (
  634.   const Obj : TacStreamable
  635.   );
  636. var
  637.   ClassId : TacStreamableClassId;
  638. begin
  639.   ValidateStreamMode([osmOutput, osmAppend]);
  640.  
  641.   if ( Assigned(Obj) ) then
  642.     begin
  643.     { Get the class id }
  644.     ClassId := AddClassRef(Obj);
  645.     { Save the class id }
  646.     GetStream.WriteBuffer(ClassId, Sizeof(ClassId));
  647.     { Save the object }
  648.     Obj.SaveToStream(self);
  649.     end;
  650. end;
  651.  
  652.  
  653. {
  654. ReadObject
  655. Reads a TacStreamable object from the stream.
  656. If Obj parameter is nil a new object is created.
  657. If Obj parameter in not nil, Obj is updated from the stream.
  658. Returns reference to the read object.
  659. }
  660. function  TacObjStream.ReadObject
  661.   (
  662.   const Obj : TacStreamable
  663.   ): TacStreamable;
  664. var
  665.   ClassId : TacStreamableClassId;
  666.   ObjType : TacStreamableClass;
  667.   NewObj  : TacStreamable;
  668. begin
  669.   ValidateStreamMode([osmInput]);
  670.  
  671.   Result := nil;
  672.  
  673.   { Read class id and get the corresponding class type reference }
  674.   GetStream.ReadBuffer(ClassId, sizeof(ClassId));
  675.   ObjType := TacStreamableClass(FClassTable.Objects[ClassId]);
  676.  
  677.   { Create a new object of the proper class from the stream data }
  678.   NewObj := ObjType.CreateFromStream(self);
  679.  
  680.   if ( Assigned(Obj) ) then
  681.     begin { Assign created object to passed obj and return obj }
  682.     try
  683.       obj.Assign(NewObj);
  684.       Result := Obj;
  685.     finally
  686.       NewObj.Free;
  687.       end;
  688.     end
  689.   else
  690.     begin { Just return created object }
  691.     Result := NewObj;
  692.     end;
  693. end;
  694.  
  695.  
  696. {
  697. SaveCStr
  698. Saves a null-terminated string to the stream.
  699. }
  700. procedure TacObjStream.SaveCStr
  701.   (
  702.   const CStr : PChar
  703.   );
  704. var
  705.   Size : Word;
  706. begin
  707.   ValidateStreamMode([osmOutput, osmAppend]);
  708.  
  709.   if ( Assigned(CStr) ) then
  710.     begin { Save size and string contents to stream }
  711.     Size := StrBufSize(CStr);
  712.     GetStream.WriteBuffer(Size, SizeOf(Size));
  713.     GetStream.WriteBuffer(CStr^, Size);
  714.     end
  715.   else
  716.     begin { Save zero size to stream }
  717.     Size := 0;
  718.     GetStream.WriteBuffer(Size, SizeOf(Size));
  719.     end;
  720. end;
  721.  
  722.  
  723. {
  724. ReadCStr
  725. Reads a null-terminated string from the stream.
  726. Returns a pointer to a newly allocated null-terminated string.
  727. }
  728. function  TacObjStream.ReadCStr: PChar;
  729. var
  730.   Size : Word;
  731. begin
  732.   Result := nil;
  733.  
  734.   ValidateStreamMode([osmInput]);
  735.  
  736.   { Read size of string }
  737.   GetStream.ReadBuffer(Size, SizeOf(Size));
  738.  
  739.   if ( 0 < Size ) then
  740.     begin { Allocate string and init contents from stream }
  741.     Result := StrAlloc(Size);
  742.     GetStream.ReadBuffer(Result^, Size);
  743.     end;
  744. end;
  745.  
  746.  
  747. { ************************* TacFileObjStream ******************************** }
  748.  
  749. {
  750. Create
  751. Creates an TacObjStream instance tied to a specific disk file.
  752. }
  753. constructor TacFileObjStream.Create
  754.   (
  755.   const Filename : TFilename
  756.   );
  757. begin
  758.   inherited Create;
  759.   FFilename := Filename;
  760. end;
  761.  
  762.  
  763. {
  764. Destroy (override)
  765. }
  766. destructor TacFileObjStream.Destroy;
  767. begin
  768.   inherited Destroy;
  769.  
  770.   { Postponed stream free so TacObjStream can close it up, if needed }
  771.   FFileStream.Free;
  772. end;
  773.  
  774.  
  775. {
  776. GetStream (override)
  777. Returns the contained TFileStream.
  778. }
  779. function  TacFileObjStream.GetStream: TStream;
  780. begin
  781.   Result := FFileStream;
  782. end;
  783.  
  784.  
  785. {
  786. OpenStream (override)
  787. Opens the contained TFileStream.
  788. }
  789. procedure TacFileObjStream.OpenStream
  790.   (
  791.   const Mode : TacObjStreamMode
  792.   );
  793. var
  794.   StreamFileMode : Word;
  795. begin
  796.   case  Mode  of
  797.     osmInput  : StreamFileMode := fmOpenRead or fmShareDenyWrite;
  798.     osmOutput : StreamFileMode := fmCreate;
  799.     osmAppend : StreamFileMode := fmOpenReadWrite or fmShareDenyWrite;
  800.     end;
  801.   FFileStream := TFileStream.Create(Filename, StreamFileMode);
  802. end;
  803.  
  804.  
  805. {
  806. CloseStream (override)
  807. Closes the contained TFileStream.
  808. }
  809. procedure TacFileObjStream.CloseStream;
  810. begin
  811.   FFileStream.Free;
  812.   FFileStream := nil;
  813. end;
  814.  
  815.  
  816. { ************************* TacMemoryObjStream ****************************** }
  817.  
  818. { NOTE: Open and close are essentially null operations on a memory stream. }
  819.  
  820. {
  821. Create
  822. Creates an TacObjStream instance tied to memory.
  823. }
  824. constructor TacMemoryObjStream.Create;
  825. begin
  826.   inherited Create;
  827.   { Create the actual TMemoryStream }
  828.   FMemoryStream := TMemoryStream.Create;
  829. end;
  830.  
  831.  
  832. {
  833. Destroy (override)
  834. }
  835. destructor TacMemoryObjStream.Destroy;
  836. begin
  837.   inherited Destroy;
  838.  
  839.   { Postponed stream free so TacObjStream can close it up, if needed }
  840.   FMemoryStream.Free;
  841. end;
  842.  
  843.  
  844. {
  845. GetStream (override)
  846. Returns the contained TMemoryStream.
  847. }
  848. function  TacMemoryObjStream.GetStream: TStream;
  849. begin
  850.   Result := FMemoryStream;
  851. end;
  852.  
  853.  
  854. {
  855. OpenStream (override)
  856. There's nothing to do. memory is always 'open' and always supports all
  857.   input/output operations.
  858. }
  859. procedure TacMemoryObjStream.OpenStream
  860.   (
  861.   const Mode : TacObjStreamMode
  862.   );
  863. begin
  864. end;
  865.  
  866.  
  867. {
  868. CloseStream (override)
  869. There's nothing to do. memory is always 'open'. and always supports all
  870. }
  871. procedure TacMemoryObjStream.CloseStream;
  872. begin
  873. end;
  874.  
  875.  
  876. end.
  877.